using AnimCollections;
using AOT;
using Unity.Burst;
using UnityEngine.Animations;
using UnityEngine.Playables;

namespace DA.AnimGraph {
    [BurstCompile]
    public unsafe partial struct SimpleBlendNode : INode {
        public struct SetupData : INodeSetupData {
            public FloatLinkDesc alphaDesc;
        }

        //
        private FloatLink linkAlpha;

        //
        private NodeHead head;
        private AnimationMixerPlayable playable;

        private void Setup(in SetupData data, ref GraphBuffer buffer, in NodeLink* link) {
            linkAlpha = new FloatLink(data.alphaDesc);
        }

        private static Playable BuildPlayableGraph(in void* node,in NodeLink* link, in PlayableGraph graph, in BuildContext buildContext) {
            var self = (SimpleBlendNode*)node;

            self->head = new NodeHead(link);

            self->playable = AnimationMixerPlayable.Create(graph, 2);
            var playableA = self->head.children[0]->BuildPlayableGraph(graph, buildContext);
            var playableB = self->head.children[1]->BuildPlayableGraph(graph, buildContext);
            self->playable.ConnectInput(0, playableA, 0);
            self->playable.ConnectInput(1, playableB, 0);

            return self->playable;
        }

        [BurstCompile]
        [MonoPInvokeCallback(typeof(NodeLink.EvaluateDelegate))]
        private static void Evaluate(in void* node, bool onEnter, in EvaluateContext evaluateContext, in GraphContext graphContext, ref UpstreamData upstream, ref ScopeContext scope) {
            var self = (SimpleBlendNode*)node;

            float alpha = self->linkAlpha.Evaluate(onEnter, evaluateContext, graphContext, scope);

            if (alpha.IsNearZero()) {
                alpha = 0;
                self->head.weights[0] = 1;
                self->head.weights[1] = 0;
            } else if (alpha.IsNear(1)) {
                alpha = 1;
                self->head.weights[0] = 0;
                self->head.weights[1] = 1;
            } else {
                self->head.weights[0] = 1 - alpha;
                self->head.weights[1] = alpha;
            }

            for (int i = 0; i < 2; i++) {
                var w = self->head.weights[i];
                if (w != 0) {
                    var childScope = new ScopeContext(scope, self->head.weights[i]);
                    NodeLink.Evaluate(self->head.children[i], evaluateContext, graphContext, ref upstream, ref childScope);
                    scope.Fusion(childScope);
                }
            }
        }

    }
}
